///////////////////////////////////////////////////////////////////////////////
//
//  Elfin
//  Kolonitsky Developers Alliance (c) 2011
//  All rights received
//
///////////////////////////////////////////////////////////////////////////////

package org.kolonitsky.alexey
{

    import flash.net.SharedObject;

    import org.kolonitsky.alexey.debug.DebugWrapper;

    import utils.Logger;

    /**
     *  Stored fields saved to local storage with key with all dependency.
     *  Any field saved with complex key
     *
     *  For example:
     *  Field user_name saved locally with id "email" without any dependency.
     *  In this case key is "email"
     *
     *  key = email
     *
     *  Field "tweet_text" individual for each user. It depend from value in
     *  field "email". It saved with dependency to "email".
     *
     *  key = tweet_text.alexey.s.kolonitsky@gmail.com
     *  
     *
     *  alexey.s.kolonitsky@gmail.com is email's value on tweet_text saving.
     */
    public class StoredFieldManager
    {
        //---------------------------------------------------------------------
        //
        //  Public
        //
        //---------------------------------------------------------------------

        public static const VISITOR_ID_KEY:String = "vid";


        //-----------------------------
        // instance
        //-----------------------------

        private static var _instance:StoredFieldManager = null;

        /**
         * Singletone property
         */
        public static function get instance():StoredFieldManager
        {
            if (_instance == null)
                _instance = new StoredFieldManager();
            return _instance;
        }


        //-----------------------------
        // visitorId
        //-----------------------------

        private var _visitorId:String = "";

        public function get visitorId():String
        {
            if (_visitorId == null || _visitorId == "")
                _visitorId = getField(VISITOR_ID_KEY);

            if (_visitorId == null || _visitorId == "")
            {
                var now:Date = new Date();
                _visitorId = applicationId + "-" + String(now.time);
                setField(VISITOR_ID_KEY, _visitorId);
            }

            return _visitorId;
        }



        //-------------------------------------------------------------------
        // Methods
        //-------------------------------------------------------------------

        /**
         * Initialize StoredFieldManager before use.
         * @param applicationName
         */
        public function initialize(applicationName:String):void
        {
            applicationId = applicationName;
            try
            {
                so = SharedObject.getLocal(applicationId);
            }
            catch (error:Error)
            {
                DebugWrapper.error("Shared object not created.", this);
                DebugWrapper.error(error.message, this);
            }
        }


        //-----------------------------
        // Array
        //-----------------------------

        [Bindable("change")]

        /**
         *  getList return array as IList from local storage. For add list to list
         *  use add
         *
         *  @param id
         *  @param dependency
         *
         *  @return List of strings.
         */
        public function getList(id:String, ...dependency:Array):Array
        {
            var key:String = generageKey(id,  dependency);
            var result:Array = getField(key) as Array;
            return result;
        }


        /**
         *
         * @param id
         * @param data
         * @param dependency
         */
        public function setList(id:String, data:*, ...dependency:Array):void
        {
            var key:String = generageKey(id, dependency);
            setField(key,  data);
        }


        //-----------------------------
        // String
        //-----------------------------

        [Bindable("change")]

        public function getString(id:String, ...dependency:Array):String
        {
            var key:String = generageKey(id, dependency);
            var result:String = getField(key) as String;
            return result;
        }

        public function setString(id:String, data:String, ...dependency:Array):void
        {
            var key:String = generageKey(id, dependency);
            setField(key, data);
        }


        //-----------------------------
        // uint
        //-----------------------------
        
        public function getUint(id:String, ...dependency:Array):uint
        {
            var key:String = generageKey(id, dependency);
            var result:uint = getField(key) as uint;
            return result;
        }

        public function setUint(id:String, data:uint,  ...dependency:Array):void
        {
            var key:String = generageKey(id, dependency);
            setField(key, data);
        }


        //-----------------------------
        // object
        //-----------------------------

        public function getObject(id:String, ...dependency:Array):Object
        {
            var key:String = generageKey(id, dependency);
            var result:Object = getField(key);
            return result;
        }

        public function setObject(id:String, data:Object, ...dependency:Array):void
        {
            var key:String = generageKey(id, dependency);
            setField(key, data);
        }

        /**
         * Add item to stored list. If the same item exists in list it don't added
         * If list not exist yet, it has been created.
         *
         * @param id
         * @param value
         * @param dependency
         */
        public function addItemToList(id:String, value:*, ...dependency:Array):void
        {
            var key:String = generageKey(id, dependency);
            var list:Array = getField(key) as Array;
            if (list)
            {
                if (list.indexOf(value) == -1)
                {
                    list.push(value);
                    setField(key, list);
                }
            }
            else
            {
                setField(key,  [value]);
            }
        }




        //---------------------------------------------------------------------
        //
        //  Private
        //
        //---------------------------------------------------------------------

        private var applicationId:String = "applicationId";
        private var so:SharedObject = null;

        /**
         *
         * @param id
         * @param dependency
         * @return
         */
        private function generageKey(id:String, dependency:Array):String
        {
            var result:String = id;
            for (var i:int; i < dependency.length; i++)
            {
                var dependencyName:String = dependency[i];
                var dependancyValue:* = getField(dependencyName)
                if (dependancyValue)
                    result += "." + dependancyValue;
            }
            return result;
        }

        /**
         *
         * @param key
         * @param value
         */
        private function setField(key:String,  value:*):void
        {
            if (so == null)
            {
                throw new Error("StoredFieldManager must be initialized before use. "
                    + "Use StoredFieldManager.initialize method");
            }

            so.data[key] = value;
            try
            {
                var result:String = so.flush();
            }
            catch (error:Error)
            {
                Logger.error(error, this);
            }
            finally
            {
                Logger.debug(this, "setField " + result);
            }
        }

        /**
         *
         * @param key
         * @return
         */
        public function getField(key:String):*
        {
            if (so == null)
            {
                throw new Error("StoredFieldManager must be initialized before use. "
                    + "Use StoredFieldManager.initialize method");
            }

            if (so && so.data && key in so.data)
                return so.data[key];
            return null;
        }

    }
}
